/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
*/

package com.jinhe.tss.core.cachepool;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;

import com.jinhe.tss.core.cachepool.strategy.CacheConstants;
import com.jinhe.tss.core.cachepool.strategy.CacheStrategy;
import com.jinhe.tss.core.util.BeanUtil;
import com.jinhe.tss.core.util.XMLDocUtil;

/** 
 * <p> CacheManager.java </p> 
 * 
 * 缓存池管理类
 * 
 * @author Jon.King 2007-1-3
 */
public class CacheManager {
    
    protected Logger log = Logger.getLogger(this.getClass());
    
    private static Map<String, IPool> pools = new HashMap<String, IPool>();
    
    /** 在配置文件里配置了的缓冲池Code列表  */
    private static List<String> configedPoolCodes = new ArrayList<String>();
    
    private CacheManager(){
    }
    
    private static CacheManager manager = null;
    
    /**
     * 获取一个缓存池管理类实例。singleTon
     * @return
     */
    public static CacheManager getInstance(){
        if(manager == null){
            manager = new CacheManager();
            manager.initPools(CacheConstants.STRATEGY_PATH);
        }
            
        return manager;
    }
    
    public static CacheManager getInstance(String cacheConfigFile){
        if(manager == null){
            manager = new CacheManager();
            manager.initPools(cacheConfigFile);
        }
        return manager;
    }

    /**
     * 根据缓存策略文件里的配置初始化各个缓存池。
     */
    private void initPools(String cacheConfigFile){
        try{
            Document doc = XMLDocUtil.createDoc(cacheConfigFile);
            List<Element> nodes = XMLDocUtil.selectNodes(doc, CacheConstants.STRATEGY_NODE_NAME);
            for(Element strategyNode : nodes ){
                Map<String, String> attrsMap = new HashMap<String, String>();
                CacheStrategy strategy = new CacheStrategy();
                for(Iterator<?> iter = strategyNode.attributeIterator(); iter.hasNext();){
                    Attribute attr = (Attribute)iter.next();
                    attrsMap.put(attr.getName(), attr.getValue());
                }
                for(Iterator<?> iter = strategyNode.elementIterator(); iter.hasNext();){
                    Element attrNode = (Element)iter.next();
                    attrsMap.put(attrNode.getName(), attrNode.getText());
                }
                
                BeanUtil.setDataToBean(strategy, attrsMap); 
                configedPoolCodes.add(strategy.getCode());
                pools.put(strategy.getCode(), strategy.getPoolInstance());
            }
        }catch(Exception e){
            log.info("根据缓存策略配置文件初始化缓存池失败 " + e);
        }
    }
    
    /**
     * 根据指定code值获取一个缓存池。
     * 如果获取不到，则打出日志“指定的code值找不到相应的缓存池，请确定code值是否正确”，
     * 并经初始化一个临时的不可见的简单缓存池。
     * @param code
     * @return
     */
    public IPool getCachePool(String code){
        IPool pool = pools.get(code);
        if(pool == null){
            // 如果是配置文件里配置的缓冲池获取不到，则先等待3秒钟，其有可能正在初始化。
            // 另外也不能随意生成一个新的普通池，否则像ThreadPool这样涉及到downCast的池将会出错
            if(configedPoolCodes.contains(code)) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                }
                return pools.get(code); // 再取一遍，如果还没生成则直接返回null
            }
            
            log.info("指定的code值找不到相应的缓存池，请确定code : " + code + "值是否正确，系统已经初始化一个临时的简单缓存池。");
            
            CacheStrategy strategy = new CacheStrategy();
            strategy.setCode(code);
            strategy.setName(code);
            strategy.setVisible(CacheConstants.FALSE);
            pools.put(code, pool = strategy.getPoolInstance());
        }
        return pool;
    }
    
    /**
     * 获取所有的池
     * @return
     */
    public Set<Map.Entry<String, IPool>> listCachePools(){
        return pools.entrySet();
    }
}

